package org.go.scheduler.rmi;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.concurrent.ConcurrentHashMap;

import org.go.expcetion.GoException;
import org.go.expcetion.JobPersistenceException;
import org.go.expcetion.SchedulerException;
import org.go.log.Log;
import org.go.log.LoggerFactory;
import org.go.scheduler.AbstractScheduler;
import org.go.scheduler.SchedulerResources;
import org.go.threadpool.GoThreadPool;
import org.go.threadpool.GoThreadPoolRepository;
import org.go.trigger.Calendar;
import org.go.trigger.Trigger;
import org.go.trigger.TriggerKey;
import org.go.work.Work;
import org.go.work.WorkKey;

/**
 * <p>
 * An implementation of the <code>Scheduler</code> interface that remotely
 * proxies all method calls to the equivalent call on a given <code>Scheduler</code>
 * instance, via RMI.
 * </p>
 * 
 * @see org.go.scheduler.Scheduler
 * 
 * @author hejie
 */
public class RMIClientScheduler extends AbstractScheduler {
	private static final Log log = LoggerFactory.getLog(RMIClientScheduler.class);
	private String remoteSchedId;
	private SchedulerResources res;
	private String rmiHost;
	private int rmiPort;
	private IRmiScheduler rsched = null;

	public RMIClientScheduler(SchedulerResources schedId, String remoteSchedId, String host, int port) {
		this.setRemoteSchedId(remoteSchedId);
		this.rmiHost = host;
		this.rmiPort = port;
		this.res = schedId;
	}

	protected IRmiScheduler getRemoteScheduler() throws SchedulerException {
		if (rsched != null) {
			return rsched;
		}
		try {
			Registry registry = LocateRegistry.getRegistry(rmiHost, rmiPort);
			rsched = (IRmiScheduler) registry.lookup(SchedulerResources.getUniqueIdentifier(remoteSchedId, null));
		} catch (RemoteException e) {
			log.error("Could not get handle to remote scheduler: " + e.getMessage(), e);
			SchedulerException initException = new SchedulerException("Could not get handle to remote scheduler: " + e.getMessage(), e);
			throw initException;
		} catch (Exception e) {
			log.error("Could not get handle to remote scheduler: " + e.getMessage(), e);
			SchedulerException initException = new SchedulerException("Could not get handle to remote scheduler: " + e.getMessage(), e);
			throw initException;
		}
		return rsched;
	}

	@Override
	public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException {

	}

	@Override
	public ConcurrentHashMap<String, Object> getContext() {
		return null;
	}

	@Override
	public String getJobGroupNames() {
		return null;
	}

	public String getRemoteSchedId() {
		return remoteSchedId;
	}

	@Override
	public SchedulerResources getResource() {
		return res;

	}

	@Override
	public String getSchedulerName() throws SchedulerException {
		return res.getName();
	}

	@Override
	public Trigger getTrigger(TriggerKey tKey) {
		try {
			return rsched.getTrigger(tKey);
		} catch (SchedulerException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean isShutdown() throws SchedulerException {
		try {
			return getRemoteScheduler().isShutdown();
		} catch (SchedulerException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	@Override
	public void notifySchedulerListenersError(String string, GoException se) {

	}

	@Override
	public void notifySchedulerListenersError(String string, JobPersistenceException se) {

	}

	@Override
	public void pauseWork(WorkKey workKey) throws SchedulerException {

	}

	@Override
	public void scheduler(Work work, Trigger trigger) throws SchedulerException {

	}

	public void setRemoteSchedId(String remoteSchedId) {
		this.remoteSchedId = remoteSchedId;
	}

	//	@Override
	//	public void startDelayed(int seconds) throws SchedulerException {
	//
	//	}

	public void setRes(SchedulerResources res) {
		this.res = res;
	}

	//	@Override
	//	public void shutdown() throws SchedulerException {
	//		GoThreadPool poolWrapper = GoThreadPoolRepository.getInstance().lookup();
	//		poolWrapper.shutdown();
	//	}

	@Override
	public void shutdown(boolean cleanShutdown) throws SchedulerException {
		try {
			getRemoteScheduler().shutdown(cleanShutdown);
		} catch (SchedulerException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void shutdownNow() throws SchedulerException {
		GoThreadPool poolWrapper = GoThreadPoolRepository.getInstance().lookup();
		poolWrapper.shutdownNow();
	}

	@Override
	public void unscheduleWork(TriggerKey tKey) {

	}

	@Override
	public void pauseAllWorks() throws SchedulerException {
		try {
			rsched.pauseAllWorks();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

}
